//
//  UserDefaults.swift
//  Documentation
//
//  Created by Toj on 10/9/23.
//

import CoreFoundation

/**
 * NSUserDefaults: 是一个分层的持久化进程间(可选的分布式)键值存储, 针对存储用户设置进行了优化.
 * 层次化: NSUserDefaults有一个用于查找数据的位置列表, 称为“搜索列表”.
 NOTE: 搜索列表由称为"套件标识符"或"域标识符"的任意字符串引用.
 */
open class UserDefaults : NSObject {

    // 标准用户默认对象(配置为搜索当前应用程序搜索列表的NSUserDefaults的全局实例）
    open class var standard: UserDefaults { get }

    // 重置, 释放标准用户默认值并将其设置为零(不推荐使用)
    open class func resetStandardUserDefaults()

    
    /// -init is equivalent to -initWithSuiteName:nil
    public convenience init()

    @available(iOS 7.0, *)
    // 用应用程序和当前用户的默认值初始化用户默认对象
    public init?(suiteName suitename: String?)

    // 移除键对应值, 相当于[obj setObject:nil forKey:defaultName]
    open func removeObject(forKey defaultName: String)

    // 读取键对应值
    open func object(forKey defaultName: String) -> Any?
    open func string(forKey defaultName: String) -> String?
    open func array(forKey defaultName: String) -> [Any]?
    open func dictionary(forKey defaultName: String) -> [String : Any]?
    open func data(forKey defaultName: String) -> Data?
    open func stringArray(forKey defaultName: String) -> [String]?
    
    open func integer(forKey defaultName: String) -> Int
    open func float(forKey defaultName: String) -> Float
    open func double(forKey defaultName: String) -> Double
    open func bool(forKey defaultName: String) -> Bool
    @available(iOS 4.0, *)
    open func url(forKey defaultName: String) -> URL?

    // 存储键对应值
    open func set(_ value: Any?, forKey defaultName: String)
    open func set(_ value: Int, forKey defaultName: String)
    open func set(_ value: Float, forKey defaultName: String)
    open func set(_ value: Double, forKey defaultName: String)
    open func set(_ value: Bool, forKey defaultName: String)
    @available(iOS 4.0, *)
    open func set(_ url: URL?, forKey defaultName: String)

    /**
     * 将指定字典的内容添加到每个注册域的最后面
     */
    open func register(defaults registrationDictionary: [String : Any])

    // 将指定的域名插入到接收方的搜索列表中
    open func addSuite(named suiteName: String)

    // 从接收器的搜索列表中移除指定的域名
    open func removeSuite(named suiteName: String)
   
    
    // 返回包含搜索列表中域中所有键值对的联合的字典
    open func dictionaryRepresentation() -> [String : Any]

    // 易失性域名
    open var volatileDomainNames: [String] { get }

    //返回指定的易失性域的字典
    open func volatileDomain(forName domainName: String) -> [String : Any]

    // 为指定的易失性域设置字典
    open func setVolatileDomain(_ domain: [String : Any], forName domainName: String)

    // 从用户的默认值中移除指定的易失性域
    open func removeVolatileDomain(forName domainName: String)

    
    // 返回指定域默认值的字典表示形式
    open func persistentDomain(forName domainName: String) -> [String : Any]?

    // 为指定的持久域设置字典
    open func setPersistentDomain(_ domain: [String : Any], forName domainName: String)

    
    // 从用户的默认值中移除指定的持久域的内容
    open func removePersistentDomain(forName domainName: String)

    /**
     * 数据同步, 根据苹果注解已经启用.
     * 如果没有调用, 系统会根据I/O情况不定时刻地保存到文件中, 会造成数据丢失.
     * 如果需要立即写入文件的就必须调用synchronize方法
     */
    open func synchronize() -> Bool

    // 该值指示指定密钥是否由管理员管理
    open func objectIsForced(forKey key: String) -> Bool

    // 该值指示指定域中的密钥是否由管理员管理
    open func objectIsForced(forKey key: String, inDomain domain: String) -> Bool
}

extension UserDefaults {

    /**
     * 当用户默认值中存储的数据多于允许的数据时, 会在主队列上发布.
     * NOTE:
     * 目前, 除了tvOS之外, 本地用户默认值没有限制,
     * 在tvOS上, 警告通知将以512kB的大小发布, 进程以1MB的大小终止.
     * 对于普遍的默认值, 限制取决于登录的iCloud用户.
     */
    @available(iOS 9.3, *)
    public class let sizeLimitExceededNotification: NSNotification.Name

    /**
     * 在设置了云默认值, 但没有iCloud用户登录的情况下, 在主队列上发布到默认通知中心.
     * 这并不一定是一个错误: 当没有iCloud用户登录时
     */
    @available(iOS 9.3, *)
    public class let noCloudAccountNotification: NSNotification.Name

    /**
     * 当用户更改主iCloud帐户时，在主队列上发布到默认通知中心.
     * 本地键值存储中的键和值已被替换为来自新帐户的键和值, 而不考虑相对时间戳.
     */
    @available(iOS 9.3, *)
    public class let didChangeCloudAccountsNotification: NSNotification.Name

    /**
     * 默认值完成下载时, 在主队列上发布.
     * 当 设备第一次连接到iCloud帐户;
     * 当 用户切换他们的主要iCloud帐户.
    */
    @available(iOS 9.3, *)
    public class let completedInitialCloudSyncNotification: NSNotification.Name

    /**
     * 会在当前进程中任何用户默认值发生变化时发布
    */
    public class let didChangeNotification: NSNotification.Name
    
    
    // 参数域 -> 应用域 -> 全局域 -> 语言域 ->注册域
    
    /**
     * 参数域(argument domain), 有最高优先权
     * 从应用程序的参数解析默认值组成的域
     */
    public class let argumentDomain: String
    
    /**
     * 应用域(application domain), 是最重要的域
     * 它存储着你app通过NSUserDefaults set...forKey添加的设置
     */
    
    /**
     * 全局域(global domain), 存储着系统的设置
     * 由所有应用程序所看到的默认值组成的域
     * 标识给定用户的所有应用程序之间共享的域.
     * 自动包含在所有搜索列表中, 在搜索列表的域条目之后.
     */
    public class let globalDomain: String
    
    /**
     * 语言域(language-specific domains), 则包括地区、日期等
     */
    
    /**
     * 注册域(registration domain)
     * 仅有较低的优先权, 只有在应用域没有找到值时才从注册域去寻找
     * 由一组临时缺省值组成的域, 其值可以由应用程序设置, 以确保搜索始终是成功的
     */
    public class let registrationDomain: String
}
